package cc.xpcas.raft.codec.json;

import java.io.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import cc.xpcas.raft.codec.Codec;

/**
 * @author xp
 */
public class JsonCodec implements Codec {

    private static final Logger LOG = LoggerFactory.getLogger(JsonCodec.class);

    private final ObjectMapper objectMapper;

    public JsonCodec(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public byte[] encode(Object o) {
        JsonBox box = new JsonBox();
        box.setClassPath(o.getClass().getName());
        box.setValue(objectMapper.valueToTree(o));
        try {
            return objectMapper.writeValueAsBytes(box);
        } catch (JsonProcessingException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(String.format("JSON encode failed: %s", e.getMessage()));
            }
            return null;
        }
    }

    @Override
    public Object decode(byte[] bs) {
        if (bs == null) return null;
        JsonBox box;
        try {
            box = objectMapper.readValue(bs, JsonBox.class);
        } catch (IOException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(String.format("JSON decode failed: %s", e.getMessage()));
            }
            return null;
        }
        Class clazz;
        try {
            clazz = Class.forName(box.getClassPath());
        } catch (ClassNotFoundException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(String.format("class not found: %s", box.getClassPath()));
            }
            return null;
        }
        try {
            JsonParser tokens = objectMapper.treeAsTokens(box.getValue());
            return objectMapper.readValue(tokens, clazz);
        } catch (IOException e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(String.format("JSON decode failed: %s", e.getMessage()));
            }
            return null;
        }
    }
}
